/*
* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
*
*/

#include "calendarbutton.h"
#include <QStylePainter>
#include <QStyleOptionButton>
#include <QApplication>
#include "kysdk/applications/windowmanager/windowmanager.h"


#define ORG_UKUI_STYLE            "org.ukui.style"
#define STYLE_NAME                "styleName"

#define HOUR_SYSTEM_CONTROL "org.ukui.control-center.panel.plugins"

#define DATA_FORMAT     "date"          //日期格式：yyyy/MM/dd、yyyy-MM-dd
#define TIME_FORMAT     "hoursystem"    //时间格式：12小时制、24小时制
#define WEEK_FORMAT     "firstday"      //一周第一天：星期一、星期日
#define CALENDAR_FORMAT "calendar"      //日历格式：公历-solarlunar、农历-lunar
#define HOUR_SYSTEM_24_Vertical     "hh:mm ddd  yyyy/MM/dd"
#define HOUR_SYSTEM_12_Horizontal   "Ahh:mm ddd  yyyy/MM/dd"

#define SYSTEM_FONT_SET  "org.ukui.style"
#define SYSTEM_FONT_SIZE "systemFontSize"
#define SYSTEM_FONT      "systemFont"

#define CALENDAR_BUTTON_WIDTH  120

#define KYSDK_TIMERSERVER "com.kylin.kysdk.TimeServer"
#define KYSDK_TIMERPATH "/com/kylin/kysdk/Timer"
#define KYSDK_TIMERINTERFACE "com.kylin.kysdk.TimeInterface"

#define  UKUI_CONTROL_CENTER_SERVER     "org.freedesktop.Accounts"
#define  UKUI_CONTROL_CENTER_PATH       "/org/freedesktop/Accounts/User1000"
#define  UKUI_CONTROL_CENTER_INTERFACE  "org.freedesktop.Accounts.User"
#define  PROPERTIES_NAME                "FormatsLocale"
#define  US_FORMATS                     "en_US.UTF-8"

#define PANEL_SIZE_LARGE  92
#define PANEL_SIZE_MEDIUM 70
#define PANEL_SIZE_SMALL  46
#define PANEL_SIZE_KEY    "panelsize"

CalendarButton::CalendarButton(IUKUIPanelPlugin *plugin, QWidget *parent):
    QPushButton(parent),
    m_parent(parent),
    m_plugin(plugin)
{
    //设置按钮样式和属性
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    this->setFlat(true);
    /*按钮边距固定0px，尽可能多显示日期信息。CalendarButton不继承ToolButton的原因就是
    主题框架提供的ToolButton的边距是固定值，无法修改*/
    this->setStyleSheet("padding: 0px;}");
    const QByteArray id(ORG_UKUI_STYLE);
    if (QGSettings::isSchemaInstalled(id)) {
        m_styleGsettings = new QGSettings(id);
        connect(m_styleGsettings, &QGSettings::changed, this, [=] (const QString &key) {
            if (key==STYLE_NAME) {
                update();
            }
        });
    }
    this->setToolTip(tr("Time and Date"));

    //初始化时间日期格式相关Gsettings
    initTimeGsettings();

    //初始化系统字体相关Gsetting
    initFontGsettings();

    //使用系统提供的sdk刷新时间显示
    QDBusConnection::systemBus().connect(KYSDK_TIMERSERVER,
                                         KYSDK_TIMERPATH,
                                         KYSDK_TIMERINTERFACE,
                                         "TimeSignal",
                                         this,
                                         SLOT(updateTimeText(QString))
                                         );
    QDBusConnection::systemBus().connect(KYSDK_TIMERSERVER,
                                         KYSDK_TIMERPATH,
                                         KYSDK_TIMERINTERFACE,
                                         "TimeChangeSignal",
                                         this,
                                         SLOT(updateTimeText(QString))
                                         );

    m_listenGsettings = new ListenGsettings();
    QObject::connect(m_listenGsettings,&ListenGsettings::iconsizechanged,[this]{updateTimeText(QString());});
    QObject::connect(m_listenGsettings,&ListenGsettings::panelpositionchanged,[this]{updateTimeText(QString());});

    //更新日历按钮内容
    updateTimeText(QString());
}

CalendarButton::~CalendarButton()
{
    if(m_styleGsettings) {
        m_styleGsettings->deleteLater();
    }
    if(m_timeGsettings) {
        m_timeGsettings->deleteLater();
    }
    if(m_fontGsettings) {
        m_fontGsettings->deleteLater();
    }
    if(m_listenGsettings) {
        m_listenGsettings->deleteLater();
    }
}

void CalendarButton::contextMenuEvent(QContextMenuEvent *event)
{
    m_menuCalender = new QMenu();
    m_menuCalender->setAttribute(Qt::WA_DeleteOnClose);
    m_menuCalender->setGeometry(m_plugin->panel()->calculatePopupWindowPos
                              (mapToGlobal(event->pos()),
                               m_menuCalender->sizeHint()));
    m_menuCalender->addAction(QIcon::fromTheme("document-page-setup-symbolic"),
                   tr("Time and Date Setting"),
                   this, SLOT(setControlTime()));
    m_menuCalender->show();
    kdk::WindowManager::setGeometry(m_menuCalender->windowHandle(),
                                        m_plugin->panel()->calculatePopupWindowPos(mapToGlobal(event->pos()), m_menuCalender->sizeHint()));
}

void CalendarButton::mousePressEvent(QMouseEvent *event)
{
    if (Qt::LeftButton == event->button()){
        Q_EMIT pressShowHideCalendar();
    }
}

//初始化时间日期格式相关Gsettings
void CalendarButton::initTimeGsettings()
{
    const QByteArray id(HOUR_SYSTEM_CONTROL);
    if (QGSettings::isSchemaInstalled(id)) {
        m_timeGsettings = new QGSettings(id);
        connect(m_timeGsettings, &QGSettings::changed, this, [=] (const QString &key) {
            if (key == DATA_FORMAT) {
                m_dataFormat = m_timeGsettings->get(DATA_FORMAT).toString();
            } else if(key == TIME_FORMAT) {
                m_timeFormat = m_timeGsettings->get(TIME_FORMAT).toString();
            } else if(key == WEEK_FORMAT) {
                m_weekFormat = m_timeGsettings->get(WEEK_FORMAT).toString();
            } else if(key == CALENDAR_FORMAT) {
                m_calendarFormat = m_timeGsettings->get(CALENDAR_FORMAT).toString();
            }
            updateTimeText(QString());
        });

        QStringList ketList = m_timeGsettings->keys();
        if(ketList.contains(DATA_FORMAT))
            m_dataFormat = m_timeGsettings->get(DATA_FORMAT).toString();
        if(ketList.contains(TIME_FORMAT))
            m_timeFormat = m_timeGsettings->get(TIME_FORMAT).toString();
        if(ketList.contains(WEEK_FORMAT))
            m_weekFormat = m_timeGsettings->get(WEEK_FORMAT).toString();
        if(ketList.contains(CALENDAR_FORMAT))
            m_calendarFormat = m_timeGsettings->get(CALENDAR_FORMAT).toString();
    }
}

//初始化系统字体相关Gsetting
void CalendarButton::initFontGsettings()
{
    const QByteArray id(SYSTEM_FONT_SET);
    if (QGSettings::isSchemaInstalled(id)) {
        m_fontGsettings = new QGSettings(id);
        connect(m_fontGsettings, &QGSettings::changed, this, [=] (const QString &keys){
            if(keys == SYSTEM_FONT_SIZE || keys == SYSTEM_FONT){
                m_systemFontSize = m_fontGsettings->get(SYSTEM_FONT_SIZE).toString();
                m_systemFont = m_fontGsettings->get(SYSTEM_FONT).toString();
                updateTimeText(QString());
            }
        });

        QStringList ketList = m_fontGsettings->keys();
        if(ketList.contains(SYSTEM_FONT_SIZE))
            m_systemFontSize = m_fontGsettings->get(SYSTEM_FONT_SIZE).toString();
        if(ketList.contains(SYSTEM_FONT))
            m_systemFont = m_fontGsettings->get(SYSTEM_FONT).toString();
    }
}

//右键跳转到控制面板日期页面
void CalendarButton::setControlTime()
{
    QProcess *process =new QProcess(this);
    process->start(
            "bash",
            QStringList() << "-c"
                          << "dpkg -l | grep ukui-control-center");
    process->waitForFinished();
    QString strResult = process->readAllStandardOutput() + process->readAllStandardError();
    if (-1 != strResult.indexOf("3.0")) {
        QProcess::startDetached(QString("ukui-control-center -t"));
    } else {
        QProcess::startDetached(QString("ukui-control-center -m Date"));
    }
}

/*
 * 更新时间文字显示
 * 横向任务栏显示格式：
 *      24小时制：
 *              hh:mm ddd    或    hh:mm ddd
 *              yyyy/MM/dd          MM/dd
 *      12小时制：
 *              AM hh:mm ddd  或    AM hh:mm
 *              yyyy/MM/dd         ddd MM/dd
 *
 * 纵向任务栏显示格式:
 *      24小时制：
 *              hh:mm        或   hh:mm
 *               ddd               ddd
 *              yyyy/MM/dd        MM/dd
 *      12小时制：
 *               AM                  AM
 *              hh:mm               hh:mm
 *               ddd          或     ddd
 *              yyyy/MM/dd          MM/dd
*/
void CalendarButton::updateTimeText(QString timerStr)
{
    Q_UNUSED(timerStr);
    //获取 上下午、时间、星期、日期（年、月、日）
    QDateTime dataTimeNow = QDateTime::currentDateTime();
    QString time = dataTimeNow.toString("A hh:mm");
    QStringList timeList = time.split(" ", QString::SkipEmptyParts);
    QString timeAMPM = timeList.at(0);
    QString time12 = timeList.at(1);
    QString time24 = dataTimeNow.toString("hh:mm");
    QString week = dataTimeNow.toString("dddd");
    QString year = dataTimeNow.toString("yyyy");
    QString mon = dataTimeNow.toString("MM");
    QString day = dataTimeNow.toString("dd");

    QList<double_t> systemFonts;
    systemFonts.append(10);
    systemFonts.append(12);
    systemFonts.append(13.5);
    systemFonts.append(15);
    double fontSize = m_fontGsettings->get(SYSTEM_FONT_SIZE).toDouble();

    //根据时间日期样式，组合时间文本
    QString displayText;
    if(m_plugin->panel()->isHorizontal()) {
        //字号限制，防止调整任务栏大小或者系统增加字号时导致显示不全
        m_panelSize = m_listenGsettings->m_panelGsettings->get(PANEL_SIZE_KEY).toInt();
        if(m_panelSize < PANEL_SIZE_MEDIUM) {
            if(fontSize >= systemFonts.first())
                this->setFont(QFont(m_systemFont, systemFonts.first()));
            else
                this->setFont(QFont(m_systemFont, fontSize));
        } else if(m_panelSize >= PANEL_SIZE_MEDIUM) {
            if(fontSize >= systemFonts.last())
                this->setFont(QFont(m_systemFont, systemFonts.last()));
            else
                this->setFont(QFont(m_systemFont, fontSize));
        }

        if(!QString::compare("24", m_timeFormat)) {
            //拼接 时间 和 星期
            displayText = time24 + " " + week + "\n";
            //拼接 年月日
            QString data =  year + " " + mon + " " + day;
            QFontMetrics fontMetrics(this->font());
            int fontSize = fontMetrics.width(data);
            bool isShowYear = true;
            if(fontSize > CALENDAR_BUTTON_WIDTH-5) {
                isShowYear = false;
            }
            if(QString::compare("cn", m_dataFormat)) {
                if(isShowYear)
                    data =  year + "-" + mon + "-" + day;
                else
                    data =  mon + "-" + day;
            } else {
                if(isShowYear)
                    data =  year + "/" + mon + "/" + day;\
                else
                    data =  mon + "/" + day;
            }
            displayText += data;
        } else {
            // 拼接 AM 时间 星期
            QString formatsLocale = getFormatsLocale();
            QString data;
            QString timeGroup;
            if(formatsLocale == US_FORMATS) {
                data = time12 + " " + timeAMPM + " " + week;
                timeGroup = time12 + " " + timeAMPM;
            } else {
                data = timeAMPM + " " + time12 + " " + week;
                timeGroup = timeAMPM + " " + time12;
            }
            QFontMetrics fontMetrics(this->font());
            int fontSize = fontMetrics.width(data);
            bool isWrap = false;
            if(fontSize > CALENDAR_BUTTON_WIDTH-5) {
                isWrap = true;
            }
            //拼接 星期 和 年月日
            if(QString::compare("cn", m_dataFormat)) {
                if(isWrap)
                    displayText =  timeGroup + "\n" + week + " " + mon + "-" + day;
                else
                    displayText =  timeGroup + " " + week + "\n" + year + "-" + mon + "-" + day;
            } else {
                if(isWrap)
                    displayText =  timeGroup + "\n" + week + " " + mon + "/" + day;
                else
                    displayText =  timeGroup + " " + week + "\n" + year + "/" + mon + "/" + day;
            }
        }
    } else {
        //字号择优策略，防止调整任务栏大小或者系统增加字号时导致显示不全
        QFontMetrics fontMetrics(QFont(m_systemFont, fontSize));
        int fontWidth = fontMetrics.width(week);
        if(fontWidth > m_plugin->panel()->panelSize()-5) {
            int index = systemFonts.indexOf(fontSize);
            if(index>0) {
                for(int i=index-1; i>=0; i--) {
                    QFont font(m_systemFont, systemFonts.at(i));
                    QFontMetrics fontMetrics(font);
                    int fontWidth = fontMetrics.width(week);
                    if(fontWidth <= m_plugin->panel()->panelSize()-5) {
                        this->setFont(QFont(m_systemFont, systemFonts.at(i)));
                        break;
                    }
                }
            }
        } else {
            this->setFont(QFont(m_systemFont, fontSize));
        }

        if(!QString::compare("24", m_timeFormat)) {
            displayText = time24 + "\n" + week + "\n";
        } else {
            displayText = timeAMPM + "\n" + time12 + "\n" + week + "\n";
        }
        if(QString::compare("cn", m_dataFormat)) {
            QString data =  year + "-" + mon + "-" + day;
            QFontMetrics fontMetrics(this->font());
            int fontSize = fontMetrics.width(data);
            if(fontSize > m_plugin->panel()->panelSize()-10) {
                data =  mon + "-" + day;
            }
            displayText += data;
        } else {
            QString data =  year + "/" + mon + "/" + day;
            QFontMetrics fontMetrics(this->font());
            int fontSize = fontMetrics.width(data);
            if(fontSize > m_plugin->panel()->panelSize()-10) {
                data =  mon + "/" + day;
            }
            displayText += data;
        }
    }

    //设置按钮文字
    this->setText(displayText);
}

/* 获取时间、日期、货币格式 */
QString CalendarButton::getFormatsLocale()
{
    QDBusInterface interface(UKUI_CONTROL_CENTER_SERVER,
                             UKUI_CONTROL_CENTER_PATH,
                             UKUI_CONTROL_CENTER_INTERFACE,
                             QDBusConnection::systemBus());
    QVariant ret = interface.property(PROPERTIES_NAME);
    return ret.toString();
}

void CalendarButton::paintEvent(QPaintEvent* event)
{
    QStylePainter painter(this);
    QStyleOptionButton option;
    initStyleOption(&option);
    if ((option.state & QStyle::State_Enabled) &&
            (option.state & QStyle::State_MouseOver ||
             option.state & QStyle::State_HasFocus)) {
        painter.save();
        painter.setPen(Qt::NoPen);

        QPalette pal = qApp->palette();
        QColor color = pal.color(QPalette::Active, QPalette::BrightText);
        color.setAlphaF(m_btnAlphaF);
        painter.setBrush(color);
        painter.setRenderHint(QPainter::Antialiasing);

        painter.drawRoundedRect(option.rect, 6, 6);
        painter.restore();
    }

    QStyleOptionButton subopt = option;
    subopt.rect = painter.style()->subElementRect(QStyle::SE_PushButtonContents, &option, this);
    subopt.palette.setBrush(QPalette::BrightText, subopt.palette.brightText());
    painter.style()->drawControl(QStyle::CE_PushButtonLabel, &subopt, &painter, this);
    return;
}
